﻿using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JT808.Gateway.Abstractions;
using JT808.Gateway.QueueService;
using JT808.Gateway.QueueService.Models;
using JT808.Protocol;
using JT808.Protocol.Enums;
using JT808.Protocol.Extensions;
using JT808.Protocol.MessageBody;
using Microsoft.Extensions.Logging;

namespace JT808.Gateway.SimpleQueueService.Impl
{
    public class JT808QueueReplyMessageHandlerImpl : IJT808DownMessageHandler
    {
        private ILogger logger;
        private JT808DbContext dbContext;
        private IJT808Config config;
        private IJT808NotifyProducer notifyProducer;

        /// <summary>
        /// 处理消息工厂
        /// </summary>
        protected Dictionary<ushort, MsgIdMethodDelegate> HandlerDict { get; }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="package"></param>
        /// <returns></returns>

        protected delegate byte[] MsgIdMethodDelegate(JT808Package package);
        /// <summary>
        /// JT808序列化器
        /// </summary>
        protected JT808Serializer JT808Serializer { get; }

        public JT808QueueReplyMessageHandlerImpl(ILoggerFactory loggerFactory, JT808DbContext context,
            IJT808Config jT808Config, IJT808NotifyProducer producer)
        {
            logger = loggerFactory.CreateLogger<JT808QueueReplyMessageHandlerImpl>();
            dbContext = context;
            config = jT808Config;
            notifyProducer = producer;
            this.JT808Serializer = jT808Config.GetSerializer();
            HandlerDict = new Dictionary<ushort, MsgIdMethodDelegate> {
                {JT808MsgId._0x0102.ToUInt16Value(), Msg0x0102},
                {JT808MsgId._0x0100.ToUInt16Value(), Msg0x0100 },
                {JT808MsgId._0x0200.ToUInt16Value(), Msg0x0200},
            };
        }

        private byte[] RegistryReply(JT808Package package, in string code,
            JT808TerminalRegisterResult result = JT808TerminalRegisterResult.success)
        {
            if (package.Version == JT808Version.JTT2019)
            {
                byte[] data = JT808Serializer.Serialize(JT808MsgId._0x8100.Create_终端注册应答_2019(package.Header.TerminalPhoneNo, new JT808_0x8100()
                {
                    Code = code,
                    JT808TerminalRegisterResult = result,
                    AckMsgNum = package.Header.MsgNum
                }));
                return data;
            }
            else
            {
                byte[] data = JT808Serializer.Serialize(JT808MsgId._0x8100.Create(package.Header.TerminalPhoneNo, new JT808_0x8100()
                {
                    Code = code,
                    JT808TerminalRegisterResult = result,
                    AckMsgNum = package.Header.MsgNum
                }));
                return data;
            }
        }

        private byte[] Msg0x0100(JT808Package package)
        {
            try
            {
                // 804 906已上线
                var body = (JT808_0x0100)package.Bodies;
                logger.LogDebug($"a terminal with terminal_id={body.TerminalId} is registrying...");
                var terminals = dbContext.TerminalInfos.Where(terminal =>
                     terminal.PhoneNo == package.Header.TerminalPhoneNo
                    //terminal.MakerId == body.MakerId && terminal.TerminalModel == body.TerminalModel &&
                    //body.TerminalId.Contains(body.TerminalId)
                ).ToList();
                if (terminals.Count == 1 && !terminals[0].Enable)
                {
                    dbContext.RegistryInfos.Add(new RegistryInfo
                    {
                        AreaId = body.AreaID,
                        CityId = body.CityOrCountyId,
                        PlateColor = body.PlateColor,
                        PlateNo = body.PlateNo,
                        Code = "6666",
                        TerminalInfo = terminals[0],
                        TerminalInfoId = terminals[0].Id
                    });
                    var terminal = dbContext.TerminalInfos.Find(terminals[0].Id);
                    if (terminal != null)
                    {
                        terminal.Enable = true;
                    }

                    dbContext.SaveChanges();
                    return RegistryReply(package, "6666");
                }
                else if (terminals.Count == 0)
                {
                    logger.LogInformation($"Registry Failed since there are {terminals.Count} terminals satisfy your condition");
                    return RegistryReply(package, "", JT808TerminalRegisterResult.terminal_not_database);
                }
                else if (terminals.Count == 1 && terminals[0].Enable)
                {
                    return RegistryReply(package, "", JT808TerminalRegisterResult.terminal_registered);
                }
                else
                {
                    logger.LogInformation($"Registry Failed since there are {terminals.Count} terminals satisfy your condition");
                    return RegistryReply(package, "", JT808TerminalRegisterResult.terminal_not_database);
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "");
                return null;
            }

        }

        /// <summary>
        /// 平台通用应答
        /// </summary>
        /// <param name="request"></param>
        public byte[] CommonReply(JT808Package request, JT808PlatformResult result = JT808PlatformResult.succeed)
        {
            if (request.Version == JT808Version.JTT2019)
            {
                byte[] data = JT808Serializer.Serialize(JT808MsgId._0x8001.Create_平台通用应答_2019(request.Header.TerminalPhoneNo, new JT808_0x8001()
                {
                    AckMsgId = request.Header.MsgId,
                    JT808PlatformResult = result,
                    MsgNum = request.Header.MsgNum
                }));
                return data;
            }
            else
            {
                byte[] data = JT808Serializer.Serialize(JT808MsgId._0x8001.Create(request.Header.TerminalPhoneNo, new JT808_0x8001()
                {
                    AckMsgId = request.Header.MsgId,
                    JT808PlatformResult = result,
                    MsgNum = request.Header.MsgNum
                }));
                return data;
            }
        }

        private byte[] Msg0x0102(JT808Package package)
        {
            try
            {
                var body = (JT808_0x0102)package.Bodies;
                List<RegistryInfo> registry;
                if (package.Header.MessageBodyProperty.VersionFlag) // 2019版本有鉴权时提供IMEI
                {
                    registry = dbContext.RegistryInfos.Where(info =>
                        info.TerminalInfo.TerminalImei == body.IMEI).ToList();

                }
                else
                {
                    registry = dbContext.RegistryInfos.Where(info =>
                        info.TerminalInfo.PhoneNo == package.Header.TerminalPhoneNo).ToList();
                }
                if (registry.Count == 1 && registry[0].Code == body.Code)
                {
                    logger.LogInformation("鉴权成功");
                    notifyProducer.ProduceAsync("verified", Encoding.UTF8.GetBytes(package.Header.TerminalPhoneNo));
                    return CommonReply(package);
                }
                else
                {
                    logger.LogError($"鉴权失败，registry.Count:{registry.Count}");
                    if (registry.Count > 0)
                        logger.LogError($"registry.Code:{registry[0].Code}, body.Code:{body.Code}");
                    return CommonReply(package, JT808PlatformResult.fail);
                }
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "");
                return null;
            }
        }

        public byte IntToBcd(int value)
        {
            byte result = 0;
            if (value <= 0xFF)
            {
                //19 00010011
                //0001 1001
                int high = value / 10;
                int low = value % 10;
                result = (byte)(high << 4 | low);
            }
            return result;
        }

        /// <summary>
        /// 位置信息汇报
        /// </summary>
        /// <param name="package"></param>
        /// <returns></returns>
        private byte[] Msg0x0200(JT808Package package)
        {
            var body = (JT808_0x0200)package.Bodies;
            Span<byte> buffer = JT808ArrayPool.Rent(36);
            DateTime time = body.GPSTime;
            int yy = time.Year - JT808Constants.DateLimitYear;
            buffer[0] = IntToBcd(yy);
            buffer[1] = IntToBcd(time.Month);
            buffer[2] = IntToBcd(time.Day);
            buffer[3] = IntToBcd(time.Hour);
            buffer[4] = IntToBcd(time.Minute);
            buffer[5] = IntToBcd(time.Second);
            BinaryPrimitives.WriteInt32BigEndian(buffer.Slice(6), body.Lng);
            BinaryPrimitives.WriteInt32BigEndian(buffer.Slice(10), body.Lat);
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            Encoding.GetEncoding("GBK").GetBytes(package.Header.TerminalPhoneNo.ToCharArray()).AsSpan().CopyTo(buffer.Slice(14));
            notifyProducer?.ProduceAsync("PositionReport", buffer.ToArray());
            JT808ArrayPool.Return(buffer.ToArray());
            return null;
        }

        public byte[] Processor(string TerminalNo, byte[] Data)
        {
            logger.LogDebug($"JT808QueueReplyMessageHandlerImpl=>{TerminalNo},{Data.ToHexString()}");
            var package = JT808Serializer.Deserialize(Data);
            if (HandlerDict.TryGetValue(package.Header.MsgId, out var func))
            {
                return func(package);
            }
            else
            {
                return null;
            }
        }
    }
}
